#pragma once

#include "Misc/CommonMacros.h"
#include "Containers/Map.h"
#include "Misc/StdHead.h"
#include "Reflection/ReflectableObjectHead.h"
#include "Subsystem.h"
#include "Reflection/SubclassOf.h"
#include "SubsystemManager.m.h"


RCLASS(ExtraHeader=["Framework/Subsystem.h"])
class WHENGINE_API RSubsystemManager : public RObject
{
    ROBJECT
public:    

    /// @brief  Initialize all subsystems
    /// @param SubsystemClass  the class of the subsystem
    /// @param Owner   the owner of the subsystem
    void InitializeSubsystems(CClass* SubsystemClass,RObject* Owner);
    void DeinitializeSubsystems();

    //should only invoked in InitializeSubsystems()
    template<typename SubsystemType>
    void MakeSureInitialized()
    {
#ifdef DEBUG
        assert(bIsInitializingSubsytems && "should be only invoked during InitializeSubsystems()");
#endif  
         if(!Subsystems.Contains(SubsystemType::StaticClass()))
         {
            RSubsystemPtr NewSubsystem=NewObject<RSubsystem>(SubsystemType::StaticClass(),Owner);
            NewSubsystem->Manager=this;
            Subsystems.Add(SubsystemType::StaticClass(),NewSubsystem);
            NewSubsystem->Initialize();
         }
    }

    template<typename SubsystemType>
    SubsystemType* GetSubsystem()
    {
        return (SubsystemType*)Subsystems[SubsystemType::StaticClass()].Get();
    }

    RFUNCTION()
    RSubsystemPtr GetSubsystemByClass(TSubclassOf<RSubsystem> InClass)
    {
        return Subsystems[InClass.Get()].Get();
    }

    //virtual void CollectReference(CReferrenceCollector& Collector) override;

    ~RSubsystemManager();
protected:
    RFIELD()
    TMap<TSubclassOf<RSubsystem>,RSubsystemPtr> Subsystems;
    
    RFIELD()
    bool bIsSubsystemInitialized=false;
    
    RObject* Owner=nullptr;
#ifdef DEBUG
    bool bIsInitializingSubsytems=false;
#endif 
};